#define ZCORE_SOURCE
#include "RapidXML.hpp"
#include <Utility\Log.hpp>
#include <Utility\FileTools.hpp>

#include <3rdparty/rapidxml/rapidxml_print.hpp>
using namespace rapidxml;
namespace zzz{
bool RapidXML::LoadFile(const string &filename)
{
  filename_=filename;
  string text;
  ZCHECK(ReadFileToString(filename, text))<<"Cannot open file "<<filename;
  filetext_.SetSize(Vector<1,zuint>(text.size())+1);
  memcpy(filetext_.Data(), text.data(), text.size());
  filetext_.back()=0;
  doc_.parse<0>(filetext_.Data());
  return true;
}

bool RapidXML::SaveFile(const string &filename)
{
  filename_=filename;
  ofstream fo(filename);
  ZCHECK(fo.good())<<"Cannot open file "<<filename;
  fo<<doc_;
  return true;
}


//children
zuint RapidXML::NodeNumber() const
{
  zuint x=0;
  for (const xml_node<> *pChild=doc_.first_node();pChild!=0;pChild=pChild->next_sibling())
    if (pChild->type()==rapidxml::node_element) x++;
  return x;
}

RapidXMLNode RapidXML::GetNode(zuint i)
{
  zuint x=-1;
  for (xml_node<> *pChild=doc_.first_node();pChild!=0;pChild=pChild->next_sibling())
  {
    if (pChild->type()==rapidxml::node_element) x++;
    if (x==i) return RapidXMLNode(pChild, this);
  }
  ZLOGF<<"Node "<<i<<" does not exist!";
  return RapidXMLNode(NULL,this);
}

RapidXMLNode RapidXML::GetNode(const string &name)
{
  for (xml_node<> *pChild=doc_.first_node();pChild!=0;pChild=pChild->next_sibling())
  {
    if (pChild->type()==rapidxml::node_element && name == pChild->name()) return RapidXMLNode(pChild,this);
  }
  ZLOGF<<"Node "<<name<<" does not exist!";
  return RapidXMLNode(NULL,this);
}

bool RapidXML::HasNode(const string &name)
{
  for (xml_node<> *pChild=doc_.first_node();pChild!=0;pChild=pChild->next_sibling())
  {
    if (pChild->type()==rapidxml::node_element && name == pChild->name()) return true;
  }
  return false;
}

RapidXMLNode RapidXML::AppendNode(const string &name)
{
  if (NodeNumber()==0) {
    xml_node<> *dec = doc_.allocate_node(node_declaration, NULL);
    dec->append_attribute(doc_.allocate_attribute(
      doc_.allocate_string("version"), 
      doc_.allocate_string("1.0")));
    doc_.append_node(dec);
  }
  xml_node<> *element=doc_.allocate_node(node_element,doc_.allocate_string(name.c_str()));
  doc_.append_node(element);
  return RapidXMLNode(element,this);
}

bool RapidXML::RemoveNode(const string &name)
{
  xml_node<> *n = doc_.first_node(name.c_str());
  if (n==NULL) return false;
  doc_.remove_node(n);
  return true;
}

bool RapidXML::RemoveNode(zuint i)
{
  zuint x=0;
  for (xml_node<> *pChild=doc_.first_node();pChild!=0;pChild=pChild->next_sibling(), x++)
  {
    if (x==i) {
      doc_.remove_node(pChild);
      return true;
    }
  }
  return false;
}

const string& RapidXML::GetFilename() const
{
  return filename_;
}
}
